Turbo Stream 跟 Turbo Frame
之前我們有用 Turbo Frame,
讓新增商品的動作能在 index 頁面執行
我們在表單最外面加上 div 並且放上 id 讓 Turbo Stream 知道要找哪個地方渲染
# app/views/admin/drinks/index.html.erb
<div id="drink_list">
<% @drinks.each do |drink| %>
<%= turbo_frame_tag "drink_#{drink.id}" do %>
<div class="w-2/4 p-4 mb-8 text-white border-2 rounded-lg bg-slate-500">
<div class="flex items-center mb-4 field">
<%= drink.name %>
</div>
<div class="flex items-center mb-4 field">
<%= drink.description %>
</div>
<div class="flex items-center field">
<%= number_to_currency(drink.price, precious: 0) %>
</div>
<div class="flex items-center field">
<%= link_to '編輯', edit_admin_drink_path(drink), class: 'bg-white rounded-lg text-slate-500 p-2 mr-4' %>
<%= link_to '刪除', admin_drink_path(drink), data: { turbo_method: :delete, confirm: '確定要刪除嗎' }, class: 'bg-white rounded-lg text-slate-500 p-2' %>
</div>
</div>
<% end %>
<% end %>
</div>
我們要直接在區塊上插入新增的資料,所以就用 prepend
prepend 後面要加兩個參數,
第一個參數是你要在哪個區塊插入,
第二個參數是你要插入什麼內容,
不過因為我們要插入的內容不是一個檔案,無法用 partial 的方式,我們先用個 block 來包它
# app/views/admin/drinks/create.turbo_stream.erb
<%= turbo_stream.prepend "drink_list" do %>
<%= turbo_frame_tag "drink_#{@drink.id}" do %>
<div class="w-2/4 p-4 mb-8 text-white border-2 rounded-lg bg-slate-500">
<div class="flex items-center mb-4 field">
<%= @drink.name %>
</div>
<div class="flex items-center mb-4 field">
<%= @drink.description %>
</div>
<div class="flex items-center field">
<%= number_to_currency(@drink.price, precious: 0) %>
</div>
<div class="flex items-center field">
<%= link_to '編輯', edit_admin_drink_path(@drink), class: 'bg-white rounded-lg text-slate-500 p-2 mr-4' %>
<%= link_to '刪除', admin_drink_path(@drink), data: { turbo_method: :delete, confirm: '確定要刪除嗎' }, class: 'bg-white rounded-lg text-slate-500 p-2' %>
</div>
</div>
<% end %>
<% end %>
跟前一篇一樣,我們要在 controller
加上要回應的動作及訊息
# app/controllers/admin/drinks_controller.rb
def create
@drink = Drink.new(drink_params)
if @drink.save
Product.create(productable: @drink)
respond_to do |format|
format.html { redirect_to admin_drinks_path, notice: "商品建立成功" }
format.turbo_stream
end
else
render :new, notice: "欄位請完整填寫", status: :unprocessable_entity
end
end
基本上到這邊,我們所要的效果就完成了,不過我們還是把程式碼整理一下
把 block 包成一個 partial
# app/views/admin/drinks/_drink.html.erb
<div class="w-2/4 p-4 mb-8 text-white border-2 rounded-lg bg-slate-500">
<div class="flex items-center mb-4 field">
<%= drink.name %>
</div>
<div class="flex items-center mb-4 field">
<%= drink.description %>
</div>
<div class="flex items-center field">
<%= number_to_currency(drink.price, precious: 0) %>
</div>
<div class="flex items-center field">
<%= link_to '編輯', edit_admin_drink_path(drink), class: 'bg-white rounded-lg text-slate-500 p-2 mr-4' %>
<%= link_to '刪除', admin_drink_path(drink), data: { turbo_method: :delete, confirm: '確定要刪除嗎' }, class: 'bg-white rounded-lg text-slate-500 p-2' %>
</div>
</div>
將 index 區塊改以 partial 方式渲染
# app/views/admin/drinks/index.html.erb
<div id="drink_list">
<% @drinks.each do |drink| %>
<%= turbo_frame_tag "drink_#{drink.id}" do %>
<%= render 'drink', drink: drink %>
<% end %>
<% end %>
</div>
修改 create.turbo_stream.erb 的 block 內容為 partial
# app/views/admin/drinks/create.turbo_stream.erb
<%= turbo_stream.prepend "drink_list", partial: 'admin/drinks/drink', locals: { drink: @drink } %>
但剛剛我們在測試的時候發現新增商品不會消失,
我們需要在 turbo_stream 檔案中跟他說新增商品後,新增商品區塊要變成什麼樣子
<%= turbo_stream.prepend "drink_list", partial: 'admin/drinks/drink', locals: { drink: @drink } %>
<%= turbo_stream.update 'new_drinks' do %>
<%= link_to '新增飲品', new_admin_drink_path, data: {turbo_frame: 'new_drinks'} %>
<% end %>
這樣就完成囉
Turbo Frame 跟 Turbo Stream 的介紹就到這邊